# -*-coding: utf-8 -*-
"""
作者：TianyiFan
日期：2023-年11-月18日
用途：新版滚动分批求解算法
"""
import copy
import math
import random as rd
import para as params
from common_fuc import *
from swo_algo_method import solution_record
from docplex.mp.model import Model as Cplex_model
from docplex.mp.conflict_refiner import ConflictRefiner

rd.seed(params.seed)

class new_swo_fuc:
    def __init__(self):
        self.solution_rd = solution_record()
        self.solving_time = 0
        self.obj = params.max_bound
        self.time_change = 0
        self.theta_k = np.zeros(params.K1, dtype=int)  # k是否预留
        self.theta_tg = np.zeros([params.T, params.G], dtype=int)  # 第t时刻，block g 的预留量
        self.theta_tn = np.zeros([params.T, params.pair_new], dtype=int)  # 第t时刻n pair的预留量
        self.theta_t = np.zeros(params.T, dtype=float)  # 第t时刻的转运量
        self.reserve_list = []  # 已经被预留的subblock集合
        self.gamma_ik = {vessel: [] for vessel in range(1, params.V + 1)}  # 存放第i艘船预留的subblock
        self.cost_i = np.zeros(params.V + 1, dtype=float)
        self.decision_seq = []
        self.iter_sequence = []
        self.best_obj = params.max_bound
        self.best_seq = []
        # print("\nbatch_model 中params.Pair_N = {}".format(params.pair_new))

    def clear_global_var(self):
        self.theta_k.fill(0)
        self.theta_tg.fill(0)
        self.theta_tn.fill(0)
        self.theta_t.fill(0)
        self.cost_i.fill(0)
        self.reserve_list.clear()
        self.gamma_ik = {vessel: [] for vessel in range(1, params.V + 1)}

    def build_batch_model(self, vessel_set, N, step, iter_num):
        '''
        分批求解原模型
        :param vessel_set: 本次要求解的轮船集合
        :param N:
        :return:
        '''
        model = Cplex_model("model_{}".format(N))
        if N > 0:
            model.set_time_limit(params.single_time_limit)  # 除了第一次之外单模型最多求20s
        else:
            model.set_time_limit(30)  # 第一次求解的模型最多求30s
        maxbound = 999999
        minbound = -999999
        output_flag = False

        # region 定义决策变量
        beta_lik, beta_uik = {}, {}
        alpha_lih, alpha_uih = {}, {}
        gamma_ik = {}
        deta_u_i, deta_l_i = {}, {}
        abs_ui1, abs_li1 = {}, {}
        sum_li1, sum_ui1 = {}, {}
        for i in vessel_set:
            for h in range(params.H):
                name1 = "alpha_uij_{0:>2}_{1}_".format(i, h)
                name2 = "alpha_lij_{0:>2}_{1}_".format(i, h)
                alpha_uih[i, h] = model.integer_var(0, params.c_ui[i], name=name1)
                alpha_lih[i, h] = model.integer_var(0, params.c_li[i], name=name2)
        for i in vessel_set:
            for k in range(params.K1):
                name3 = "beta_l{0}_{1}".format(i, k)
                name4 = "beta_u{0}_{1}".format(i, k)
                name5 = "ganma_{0}_{1}".format(i, k)
                beta_lik[i, k] = model.integer_var(0, params.z, name=name3)
                beta_uik[i, k] = model.integer_var(0, params.z, name=name4)
                gamma_ik[i, k] = model.binary_var(name=name5)
        for i in vessel_set:
            name6 = "deta_u_{0}".format(i)
            name7 = "deta_l_{0}".format(i)
            name8 = "abs_u_{0}".format(i)
            name9 = "abs_l_{0}".format(i)
            name10 = "sum_u_{0}".format(i)
            name11 = "sum_i_{0}".format(i)
            deta_u_i[i] = model.integer_var(0, maxbound, name=name6)
            deta_l_i[i] = model.integer_var(0, maxbound, name=name7)
            abs_ui1[i] = model.integer_var(0, maxbound, name=name8)
            abs_li1[i] = model.integer_var(0, maxbound, name=name9)
            sum_ui1[i] = model.integer_var(minbound, maxbound, name=name10)
            sum_li1[i] = model.integer_var(minbound, maxbound, name=name11)
        # endregion

        # region 定义目标函数
        obj_expr = model.linear_expr()  # 创建一个空的线性表达式对象
        for i in vessel_set:
            expr1 = model.linear_expr()  # 创建一个空的线性表达式对象
            expr1.add_term(deta_l_i[i], params.time_p)
            expr1.add_term(deta_u_i[i], params.time_p)
            expr1.add_term(abs_li1[i], params.time_u)
            expr1.add_term(abs_ui1[i], params.time_u)
            expr2 = model.sum(beta_lik[i, k] * params.t_lki[k, i] for k in range(params.K1))
            expr3 = model.sum(beta_uik[i, k] * params.t_uki[k, i] for k in range(params.K1))
            obj_expr.add(expr1)
            obj_expr.add(expr2)
            obj_expr.add(expr3)
            if params.add_cost:
                expr4 = model.sum(gamma_ik[i, k] * params.t_subblock for k in range(params.K1))
                obj_expr.add(expr4)
        model.minimize(obj_expr)
        # endregion

        # region 定义约束条件
        # 根据theta_k 提前固定的决策变量
        for i in vessel_set:
            for k in self.reserve_list:
                model.add(gamma_ik[i, k] == 0, name="froze_constrain_{}_{}".format(i, k))
        # 补充的cut:
        for i in vessel_set:
            expr1 = model.sum(gamma_ik[i, k] for k in range(params.K1))
            model.add(expr1 >= math.ceil((params.c_ui[i] + params.c_li[i]) / params.z), name="lower_container_num_{}".format(i))

        # 目标函数中的等价替换
        for i in vessel_set:
            for h in range(params.H):
                model.add(deta_l_i[i] >= alpha_lih[i, h], name="linearing cons1_{0}_{1}".format(i, h))
                model.add(deta_u_i[i] >= alpha_uih[i, h], name="linearing cons2_{0}_{1}".format(i, h))
        for i in vessel_set:
            expr3 = model.sum(beta_lik[i, k] for k in range(params.K0))
            expr4 = model.sum(beta_uik[i, k] for k in range(params.K0))
            model.add(sum_li1[i] == alpha_lih[i, 0] - expr3, name="Constrain_sum_l_{0}".format(i))
            model.add(sum_ui1[i] == alpha_uih[i, 0] - expr4, name="Constrain_sum_u_{0}".format(i))
        for i in vessel_set:
            model.add(abs_li1[i] == model.abs(sum_li1[i]), name="abs_constrain_l_{0}".format(i))
            model.add(abs_ui1[i] == model.abs(sum_ui1[i]), name="abs_constrain_u_{0}".format(i))

        # 约束2/4：每艘船的unloading量守恒、loading量守恒
        for i in vessel_set:
            expr1 = model.sum(alpha_uih[i, h] for h in range(params.H))
            expr2 = model.sum(alpha_lih[i, h] for h in range(params.H))
            model.add(expr1 == params.c_ui[i], name="Constrain2_u_{0}".format(i))
            model.add(expr2 == params.c_li[i], name="Constrain4_l_{0}".format(i))
        # 约束 3/5：每艘船unloading/loading到堆场的数量守恒
        for i in vessel_set:
            expr3 = model.sum(beta_uik[i, k] for k in range(params.K1))
            expr4 = model.sum(beta_lik[i, k] for k in range(params.K1))
            model.add(expr3 == params.c_ui[i], name="Constrain2_u_{0}".format(i))
            model.add(expr4 == params.c_li[i], name="Constrain4_l_{0}".format(i))
        # 约束6：unloading 和 loading 在每一层的上界
        for i in vessel_set:
            for k in range(params.K1):
                model.add(beta_lik[i, k] + beta_uik[i, k] <= params.z * gamma_ik[i, k], name="Constrain6_{0}_{1}".format(i, k))

        # 约束9：每层的subblock需要小于对应的params.r_ih
        for i in vessel_set:
            expr1 = model.sum(gamma_ik[i, k] for k in range(params.K0))
            expr2 = model.sum(gamma_ik[i, k] for k in range(params.K0, params.K1))
            model.add(expr1 <= params.r_ih[i][0], name="Constrain9_0_{0}".format(i))
            model.add(expr2 <= params.r_ih[i][1], name="Constrain9_1_{0}".format(i))

        # 约束10：每个subblock只能分配给一个堆场---只针对未预留的堆场约束
        for k in range(params.K1):
            if self.theta_k[k] == 0:
                expr = model.sum(gamma_ik[i, k] for i in vessel_set)
                model.add(expr <= 1, name="Constrain10_{0}".format(k))

        # 约束11：每个time step，同一层的同一个block内，分配subblock数量不能超过3
        for t in range(params.T):
            if params.total_handle[t] >= 1:
                for g in range(params.G):
                    expr = model.sum(params.l_it[i][t] * gamma_ik[i, k] for i in vessel_set for k in params.block_set[g])
                    model.add(expr <= 3 - self.theta_tg[t, g], name="Constrain11_{0}_{1}".format(t, g))

        # 约束12：每个time step，同一层的同一个neighbor_pair 内，分配subblock数量不能超过1
        for t in range(params.T):
            if params.total_handle[t] >= 1:
                for n in range(params.pair_new):
                    expr = model.linear_expr()
                    temp_pair = params.sorted_unique_pairs[n]
                    for i in vessel_set:
                        for k in temp_pair:
                            expr.add_term(gamma_ik[i, k], params.l_it[i][t])
                    model.add(expr <= 1 - self.theta_tn[t, n], name="Constrain12_{0}_({1}_{2})".format(t, temp_pair[0], temp_pair[1]))

        # 约束13：每个time step，转运数量不能超过C
        for t in range(params.T):
            expr = model.linear_expr()
            for i in vessel_set:
                if params.l_it[i][t] == 1:
                    expr.add_term(abs_ui1[i], 1 / params.handle_i[i])
                    expr.add_term(abs_li1[i], 1 / params.handle_i[i])
            model.add(expr <= params.C - self.theta_t[t], name="Constrain13_{0}".format(t))
        # endregion
        time_start = time.time()
        solution = model.solve(log_output=output_flag)
        time_end = time.time()
        # num_variables = model.number_of_variables
        # num_constraints = model.number_of_constraints
        # print("Model_{} 中决策变量个数={}  约束数量={}".format(N, num_variables, num_constraints))
        if solution is not None:
            self.solving_time = round(time_end - time_start, 2)
            self.obj = solution.get_objective_value()
            print(f"Model_{N:2} 求解结果概要 ----------- obj={self.obj:.2f}  Time={self.solving_time} s-------------")
            cost_i = {}
            solution_ganma_ik = {vessel_idx: [] for vessel_idx in vessel_set}
            for i in vessel_set:
                cost1 = params.time_p * (max(solution.get_var_value(alpha_lih[i, 0]), solution.get_var_value(alpha_lih[i, 1])) +
                                         max(solution.get_var_value(alpha_uih[i, 0]), solution.get_var_value(alpha_uih[i, 1])))
                cost2 = params.time_u * (solution.get_var_value(abs_ui1[i]) + solution.get_var_value(abs_li1[i]))
                cost3 = 0
                for k in range(params.K1):
                    if solution.get_var_value(gamma_ik[i, k]) > 0.5:
                        solution_ganma_ik[i].append(k)
                        cost3 += params.t_lki[k, i] * solution.get_var_value(beta_lik[i, k]) + params.t_uki[k, i] * solution.get_var_value(beta_uik[i, k])
                cost_i[i] = cost1 + cost2 + cost3
            # for i in vessel_set:
            #     print("vessel-{:3}  cost = {:10.2f} abs_u={:4.2f}  abs_i = {:4.2f}  预留subblock = {} ".
            #           format(i, cost_i[i], solution.get_var_value(abs_ui1[i]), solution.get_var_value(abs_li1[i]),solution_ganma_ik[i]))
            # 基于当前的解，将前step艘船的解，更新到全局资源限制中/ 如果是最后一次迭代，将当前序列中所有的解，都更新到全局最优解中
            if N == iter_num - 1:
                step = len(vessel_set)
            for iter in range(step):
                i = vessel_set[iter]
                # print("第 {} 次 求解， 固定船-{}的结果".format(N, i))
                self.cost_i[i] = cost_i[i]
                # print("固定： vessel_idx = {} cost = {} ".format(i,self.cost_i[i]))
                for k in solution_ganma_ik[i]:
                    self.theta_k[k] = 1
                    self.gamma_ik[i].append(k)
                    self.reserve_list.append(k)
                handle_interval = params.test_data.data.iloc[i - 1]['handle_list']
                trans_port = solution.get_var_value(abs_ui1[i]) + solution.get_var_value(abs_li1[i])
                trans_port = trans_port / len(handle_interval)
                for t in handle_interval:
                    self.theta_t[t] += trans_port
                    # print("theta_t_{} += {}".format(t,trans_port))
                    for k in self.gamma_ik[i]:
                        block_index = params.subblock_info[k].blockbelong
                        self.theta_tg[t, block_index] += 1
                        # print("theta_t_{}_{} += 1   k={:3}".format(t, block_index,k))
                        pair_set = params.subblock_info[k].pair_belong
                        for n in pair_set:
                            self.theta_tn[t, n] += 1
                            # print("theta_t_{}_{} += 1   pair={}".format(t, n,params.sorted_unique_pairs[n]))
        else:
            refiner = ConflictRefiner()  # 先实例化ConflictRefiner类
            res = refiner.refine_conflict(model,display=True)  # 将模型导入该类，调用方法
            # res.display()
            print(f"batch_model_{N} 无解!")
            self.obj = params.max_bound
            # model.export("debug_model.lp")
            # raise EOFError(f"batch_model_{N} 无解!")

        model.clear()

    def operate_main_fuc(self, lb_cost, lb_obj):
        '''
        基础长度=DS
        移动步长=step
        迭代索引=N，N=0开始
        每一次迭代的头：0+N
        每一次迭代的尾：min(DS+N,V)
        代入的seq = seq[0+N:min(DS+N,V)]
        总计算次数=[math.ceiling((V-DS)/L)]+1
        每一次的基础长度=min(DS,V-DS-N)
        :return:
        '''
        time_start = time.time()
        # 滚动时域求解的初始参数
        DS = params.search_DS  # 基础的队列求解长度
        step = params.step_DS  # 移动步长--单次决策固定的对象数量
        iter_num = math.ceil((params.V - DS) / step) + 1
        iter_obj_change = []
        iter_time_change = []
        roll_idx = 0
        initial_seq, temp_data = sequence_strategy_2(params.test_data.data)
        self.decision_seq = copy.deepcopy(initial_seq)
        while roll_idx < params.rolling_number:
            print("\n-------------当前执行第 {} 套 seq 生成方案------------".format(roll_idx))
            if roll_idx == 0:     # 初始的序列
                decision_seq = initial_seq
            elif roll_idx == 1:
                decision_seq = self.seq_strategy_3(self.decision_seq)
            elif roll_idx == 2:
                decision_seq = self.seq_strategy_2(self.cost_i, self.decision_seq, lb_cost, lb_obj)
            elif roll_idx == 3:
                probility = rd.random()
                if probility < 0.5:
                    decision_seq = self.seq_strategy_1(lb_cost, lb_obj)
                else:
                    decision_seq = self.seq_strategy_4(self.decision_seq)
            else:  # 随机选择1/2/3
                probility = rd.random()
                if probility < 0.2:
                    decision_seq = self.seq_strategy_1(lb_cost, lb_obj)
                elif probility < 0.8:
                    decision_seq = self.seq_strategy_3(self.decision_seq)
                else:
                    decision_seq = self.seq_strategy_2(self.cost_i, self.decision_seq, lb_cost, lb_obj)
            if roll_idx>0:
                print(f"策略扰动前，决策序列={self.decision_seq}")
                print(f"策略扰动后，决策序列={decision_seq}")
            self.clear_global_var()           # 清空所有全局数组，重新开始迭代
            time_change = []
            N = 0  # 迭代次数
            start_que = 0
            end_que = min(DS + N, params.V)
            print(f"第 {roll_idx} 套决策队列={decision_seq}")
            success_solve = True
            while N < iter_num:
                time_111 = time.time()
                input_seq = decision_seq[start_que:end_que]
                # print("第{}次计算，start_idx={} end_idx={} 队列长度={} 决策队列={} ".format(N, start_que, end_que, len(input_seq), input_seq))
                self.build_batch_model(input_seq, N, step, iter_num)
                if self.obj == params.max_bound:
                    success_solve = False
                    print("第 {} 次 滚动求解时， 模型无解，退出循环----------------".format(N))
                    break  # 若某一轮求解没有成功，则直接退出循环，更新序列
                time_222 = time.time()
                time_change.append(remain_two(time_222 - time_111))
                start_que += step
                end_que += step
                N += 1
            roll_idx += 1  # 更换决策序列的输入方式
            self.iter_sequence.append(decision_seq)
            iter_time_change.append(sum(time_change))
            if success_solve:   # 只有完全求解成功了，才计算全局的obj
                if params.add_cost:
                    self.obj = sum(self.cost_i) + len(self.reserve_list) * params.t_subblock
                else:
                    self.obj = sum(self.cost_i)
            iter_obj_change.append(self.obj)     # 否则添加到全局的obj将等于无解情况的obj
            if success_solve:   # 只有完全求解成功的情况下，才去更新全局最优解和最优序列
                if self.obj < self.best_obj:
                    self.best_obj = self.obj
                    self.best_seq = copy.deepcopy(self.decision_seq)
                    self.decision_seq = copy.deepcopy(decision_seq)  # 更新Batch_model 的决策序列
            else:
                print("当前决策序列：{} 无法滚动求出可行解----------".format(self.decision_seq))
                if N==0:
                    print("初始序列不可行，直接停止该算例的迭代！！！！1")
                    return
                else:
                    continue

            print("===========第 {} 次决策 batch_model 的求解结果 = {:.2f}  总耗时:{:.2f} s  ================".format(roll_idx, self.obj,sum(time_change)))
            # for i in range(1, params.V + 1):
            #     print("vessel - {:3}  cost={:.2f}  预留堆场的结果 = {}".format(i, self.cost_i[i], self.gamma_ik[i]))
            print(f"batch_model 单次求解耗时变化：{time_change} ")
            print(f"batch_model 求解结果 = {self.obj:.2f}")
            # 将本次迭代的结果，添加到全局的最优解当中

            for i in range(1, params.V + 1):
                for k in self.gamma_ik[i]:
                    self.solution_rd.gamma_ik[i, k] = 1
        time_end = time.time()

        self.solving_time = time_end - time_start
        for r in range(params.rolling_number):
            print("第 {} 套决策方案 obj={:.2f}  耗时：{:5.2f} s  决策队列={}".format(r, iter_obj_change[r], iter_time_change[r],self.iter_sequence[r]))
        self.obj = self.best_obj
        print("batch_rolling 算法总迭代耗时：{:.2f}s   求解结果={:.2f}".format(time_end - time_start, self.obj))

    def seq_strategy_1(self, lB_cost_i, lb_obj):
        '''
        基于Lower_bound model得到的解，进行cost_i 分析，结合轮盘赌思想，挑选轮船后更新其排序权重seq_value，并返回新的决策序列
        :param LB_cost: dict 格式， 索引从1-param.V+1
        :return: new_decision_seq : list 格式
        '''
        temp_data_seq = copy.deepcopy(params.test_data.data)
        cost_lb = lB_cost_i[1:]
        cost_batch = self.cost_i[1:]
        cost_delta = cost_batch - cost_lb
        gap_total = self.obj - lb_obj
        # print(f"total_gap = {gap_total}")
        base_seq = params.test_data.data['seq_value'].max() - params.test_data.data['seq_value'].min()
        new_seq = {}
        for i in range(1, params.V + 1):
            new_seq[i] = round((cost_delta[i - 1] / gap_total) * base_seq, 2)
            # print("vessel_{} 的赋值权重={:.2f}   排序change={:.2f}".format(i,new_seq[i],new_seq[i]*base_seq))
        temp_data_seq['add_weight'] = new_seq.values()
        temp_data_seq['seq_value'] = temp_data_seq['seq_value'] + temp_data_seq['add_weight']
        temp_data_seq.sort_values(by=['seq_value', 'num_container'], ascending=[False, False], inplace=True)
        new_decision_seq = list(temp_data_seq['vessel_idx'])
        # 判断是否为已经出现过的seq_list---若已经出现过，则采用策略3
        for before_seq in self.iter_sequence:
            if before_seq==new_decision_seq:
                print("策略1生成的序列已在tabulist中，改用策略3重新生成序列")
                new_decision_seq = self.seq_strategy_3(self.decision_seq)
        return new_decision_seq

    def seq_strategy_2(self, cost_seq, input_seq, lb_cost, lb_obj):
        '''
        序列迭代策略2：随机算则一艘船，跟一艘在其前面决策但cost小于它的船交换位置
        :param cost_seq:  dict: key=船号，cost=船的成本
        :return:
        '''
        # 随机从2-V的船中，随机选择一艘，判断前面是否有比自己cost更小的船，如果没有，则重新选择
        initial_seq = copy.deepcopy(input_seq)
        rd.seed(params.seed)
        visit_np = [False for _ in range(params.V)]
        search_success = False
        invalide_count = 0
        while search_success is False:
            # 防止陷入死循环
            if invalide_count == params.V+2:
                break

            location_idx = rd.randint(2, params.V - 1)  # 左闭右闭
            # 重新循环条件1：已经被交换过的位置
            if visit_np[location_idx]:
                invalide_count += 1
                continue
            else:
                visit_np[location_idx] = True
            vessel_idx = initial_seq[location_idx]  # 轮船索引
            compare_cost = cost_seq[vessel_idx]
            candidate_vessel = []
            visit_np[location_idx] = True
            for i in range(location_idx):
                vessel_2 = initial_seq[i]
                if cost_seq[vessel_2] <= compare_cost:
                    # print("vessel-{}  cost={} >= vessel-{}  cost={}".format(vessel_idx, cost_seq[vessel_idx], vessel_2, cost_seq[vessel_2]))
                    candidate_vessel.append(i)  # 将对应的位置放入交换set
            # 重新循环条件2：未找到比其cost更小的位置
            if len(candidate_vessel) == 0:
                print("前序序列中，未找到比vessel-{}  cost更小的船只".format(vessel_idx))
                invalide_count += 1
                continue
            else:
                neighbor_size = len(candidate_vessel)
                change_location = rd.randint(0, neighbor_size - 1)
                initial_seq[location_idx], initial_seq[change_location] = initial_seq[change_location], initial_seq[location_idx]
                print(f"执行策略2后，交换vessel-{initial_seq[location_idx]} 和 vessel-{initial_seq[change_location]} 的决策顺序")
                for before_seq in self.iter_sequence:
                    if before_seq == initial_seq:
                        print("策略2生成的序列已在tabulist中，改用策略3重新生成序列")
                        initial_seq = self.seq_strategy_3(self.decision_seq)
                search_success=True

        if search_success is False:
            print("未找到策略2 的可行邻域, 执行邻域策略1/3")
            probility = rd.random()
            if probility > 0.5:
                decision_seq = self.seq_strategy_1(lb_cost, lb_obj)
            else:
                decision_seq = self.seq_strategy_3(self.decision_seq)
            return decision_seq
        else:
            return initial_seq

    def seq_strategy_3(self, initial_seq):
        '''
        序列迭代策略3：随机选择一艘船，将跟其存在冲突的船移至其后方进行决策
        :param intial_seq:
        :return:
        '''
        # step1:寻找冲突值>=max-1 的vessel,形成备选集
        max_value = params.test_data.data['seq_value'].max()
        candidate_vessel = []
        conflict_sort = dict(zip(params.test_data.data['vessel_idx'], params.test_data.data['seq_value']))
        for vessel, value in conflict_sort.items():
            # print(f"vessel={vessel}  seq_value ={value}")
            if value >= max(max_value - 2, 2):
                candidate_vessel.append(vessel)
        print(f"可备选的vessel集={candidate_vessel}")
        neighbor_size = len(candidate_vessel)
        visit_np = {vessel:False for vessel in candidate_vessel}
        search_success = False
        invalide_count = 0
        new_decision_seq = []
        while search_success is False:
            # step2:从中随机选择一艘船，作为邻域交换的船
            change_location = rd.randint(0, neighbor_size - 1)
            change_vessel = candidate_vessel[change_location]
            # 结束循环条件：所有船只均已被搜索过：
            if invalide_count == neighbor_size*2:
                print("当前策略3 无法生成有效的决策序列！！！！！")
                break

            # 重新循环条件1：已经搜索过的船只
            if visit_np[change_vessel]:
                invalide_count += 1
                continue
            else:
                visit_np[change_vessel] = True

            # step3:得到该轮船的conflict_list
            conflict_vessel = params.test_data.data.loc[params.test_data.data['vessel_idx'] == change_vessel, 'conflict_list'].values[0]

            # step4:将和其冲突的元素从序列中删除，然后加入到该元素后方
            conflict_vessel.sort(key=lambda x: conflict_sort[x], reverse=True)
            new_decision_seq = copy.deepcopy(initial_seq)
            for iter in conflict_vessel:
                new_decision_seq.remove(iter)
            change_location = new_decision_seq.index(change_vessel)
            new_decision_seq = new_decision_seq[:change_location + 1] + conflict_vessel + new_decision_seq[change_location + 1:]
            print("当前进行邻域变换的base-vessel={}  conflict_vessel ={}  序列改变后：{}".format(change_vessel, conflict_vessel, new_decision_seq))
            search_success = True
            # print(self.iter_sequence)
            for before_seq in self.iter_sequence:
                if before_seq == new_decision_seq:
                    print("策略3生成的序列已在tabulist中，重新生成序列")
                    search_success = False
        return new_decision_seq

    def seq_strategy_4(self,initial_seq):
        '''
        序列迭代策略4：随机选择一艘船，将跟其存在冲突的船移至其后方进行决策
        指定一艘船，将与其不冲突的船放在一块进行全局优化
        :param initial_seq:
        :return:
        '''
        search_success = False
        new_decision_seq = copy.deepcopy(initial_seq)
        while search_success is False:
            # step1:从前DS艘船内，随机选择一艘船,得到该船的no_conflict_list
            select_location = rd.randint(0,params.search_DS)
            select_vessel = initial_seq[select_location]
            print("当前基于-{} 进行策略4的变换,输入序列={}".format(select_vessel,initial_seq))
            no_confilict_list = params.test_data.data.loc[params.test_data.data['vessel_idx'] == select_vessel, 'no_conflict_list'].values[0]
            if len(no_confilict_list) == 0:
                continue

            # step2: 将不冲突的vessel_set按照num_container+seq_value 进行升序排序(得到对应的dataframe，排序后，转换为list)
            temp_data = params.test_data.data[params.test_data.data['vessel_idx'].isin(no_confilict_list)]
            temp_data = temp_data.sort_values(by=['seq_value', 'num_container'], ascending=[False, False])
            # print("不冲突的vessel，排序后的结果如下：")
            # print(temp_data)
            candidate_set = copy.deepcopy(list(temp_data['vessel_idx']))
            candidate_set = candidate_set[:params.step_DS]  # 按照步长取x艘船。让这几艘船能恰好和select_vessel 在一个周期里计算
            print("当前待更换排序决策位置的vessel _set ={}".format(candidate_set))

            # step3: 取前DS艘船船，移至当前船的后方(先消除原来队列中的值，再将candidate_set 中的元素加入)
            for vessel in candidate_set:
                new_decision_seq.remove(vessel)
            change_location = new_decision_seq.index(select_vessel)
            new_decision_seq = new_decision_seq[:change_location + 1] + candidate_set + new_decision_seq[change_location + 1:]
            search_success=True

            # step4：判断当前解是否在tabulist中
            for before_seq in self.iter_sequence:
                if before_seq == new_decision_seq:
                    print("策略4生成的序列已在tabulist中，重新生成序列")
                    search_success = False
        return new_decision_seq